package xml;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringWriter;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public abstract class Item {
    private String name;
    
    public Item( String name ) {
        this.setName(name);
    }
    
    public Node toXml()
    {
        try
        {
            DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();
            DocumentBuilder parser = fact.newDocumentBuilder();
            Document doc = parser.newDocument();

            return toXml( doc );
        }
        catch( Exception ex )
        {
            return null;
        }
    }
    
    public abstract Node toXml( Document doc );

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
    public String toString()
    {
        try
        {
          // Set up the output transformer
          TransformerFactory transfac = TransformerFactory.newInstance();
          transfac.setAttribute("indent-number", new Integer(4));
          Transformer trans = transfac.newTransformer();
          trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
          trans.setOutputProperty(OutputKeys.INDENT, "yes");
          
          // Print the DOM node

          StringWriter sw = new StringWriter();
          StreamResult result = new StreamResult(sw);
          DOMSource source = new DOMSource(toXml());
          trans.transform(source, result);
          String xmlString = sw.toString();

          return xmlString;
        }
        catch (TransformerException e)
        {
          e.printStackTrace();
          return "";
        }
    }
    
    public static Item fromXml( String xml )
    {
        InputStream is = new ByteArrayInputStream( xml.getBytes() );
        
        try
        {
            DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();
            DocumentBuilder parser = fact.newDocumentBuilder();
            Document doc = parser.parse( is );
            
            return fromXml( doc.getFirstChild() );
        }
        catch( Exception ex )
        {
            ex.printStackTrace();
            return null;
        }
    }
    
    public boolean isColeccion()
    {
        return this.getClass().getName() == "xml.Coleccion";
    }
    
    public boolean isNodo()
    {
        return this.getClass().getName() == "xml.Nodo";
    }
    
    public static Item fromXml( Node n )
    {
        
        if( n.hasChildNodes() && !n.getFirstChild().hasChildNodes() && n.getFirstChild().getNextSibling() == null )
        {
            //System.out.println( "name: " + n.getNodeName() + " value: " + n.getFirstChild().getTextContent() );
            return new Nodo( n.getNodeName(), n.getFirstChild().getTextContent() );
        }
        else if( n.hasChildNodes() )
        {
            //System.out.println( "cname: " + n.getNodeName() );
            Coleccion c = new Coleccion( n.getNodeName() );
            NodeList nodeList = n.getChildNodes();
            
            for( int i = 0; i < nodeList.getLength(); i++ )
            {
                Node node = nodeList.item( i );
                Item item = fromXml( node );
                if( item != null )
                    c.addItem( item );
            }
            
            return c;
        }
        
        return null;
    }
    
}
